/*
用户 模块
用户注册时，对于用户密码
使用钩子函数，对密码进行加密存储
使用 Scrypt 算法加密密码
*/

package model

import (
    "log"

    "gitee.com/keeving/quanta-test-cat/utils/errmsg"
    "github.com/gin-gonic/gin"
    "golang.org/x/crypto/bcrypt"
    "gorm.io/gorm"
)

type User struct {
    gorm.Model
    Username string `gorm:"type:varchar(20);not null " json:"phone" validate:"required,min=4,max=12" label:"用户名"`
    Password string `gorm:"type:varchar(500);not null" json:"password" validate:"required,min=6,max=120" label:"密码"`
    Role     int    `gorm:"type:int;DEFAULT:2" json:"role,omitempty" validate:"omitempty,gte=2" label:"角色码"` // 选填
    Avatar   string `gorm:"type:varchar(255)" json:"avatar" validate:"omitempty,url" label:"头像URL"`
}

// CheckUser 查询用户是否存在
func CheckUser(name string) (code int) {
    var user User
    db.Select("id").Where("username = ?", name).First(&user)
    if user.ID > 0 {
        return errmsg.ERROR_USERNAME_USED //1001
    }
    return errmsg.SUCCESS
}

// CheckUpUser 更新查询
func CheckUpUser(id int, name string) (code int) {
    var user User
    db.Select("id, username").Where("username = ?", name).First(&user)
    if user.ID == uint(id) {
        return errmsg.SUCCESS
    }
    if user.ID > 0 {
        return errmsg.ERROR_USERNAME_USED //1001
    }
    return errmsg.SUCCESS
}

// CreateUser 新增用户
func CreateUser(data *User) int {
    //data.Password = ScryptPw(data.Password)
    err := db.Create(&data).Error
    if err != nil {
        return errmsg.ERROR // 500
    }
    return errmsg.SUCCESS
}

// GetUser 查询用户
func GetUser(id int) (User, int) {
    var user User
    err := db.Limit(1).Where("ID = ?", id).Find(&user).Error
    if err != nil {
        return user, errmsg.ERROR
    }
    return user, errmsg.SUCCESS
}

func GetUserFromName(username string) (User, int) {
    var user User
    err := db.Limit(1).Where("username = ?", username).Find(&user).Error
    if err != nil {
        return user, errmsg.ERROR
    }
    return user, errmsg.SUCCESS
}

// GetUserName 根据用户ID查找用户
func GetUserName(id uint) (string, int) {
    var user User
    err := db.Limit(1).Where("ID = ?", id).Find(&user).Error
    if err != nil {
        return "", errmsg.ERROR
    }
    return user.Username, errmsg.SUCCESS
}

// GetUserIDByUsername 根据用户名查找用户 ID
func GetUserIDByUsername(username string) (uint, int) {
    var user User
    err := db.Where("username = ?", username).First(&user).Error
    if err != nil {
        if err == gorm.ErrRecordNotFound {
            return 0, errmsg.ERROR_USER_NOT_EXIST
        }
        return 0, errmsg.ERROR
    }
    return user.ID, errmsg.SUCCESS
}

// GetUsers 查询用户列表
func GetUsers(username string, pageSize int, pageNum int) ([]User, int64) {
    var users []User
    var total int64

    if username != "" {
        db.Select("id,username,role,created_at").Where(
            "username LIKE ?", username+"%",
        ).Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&users)
        db.Model(&users).Where(
            "username LIKE ?", username+"%",
        ).Count(&total)
        return users, total
    }
    db.Select("id,username,role,created_at").Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&users)
    db.Model(&users).Count(&total)

    if err != nil {
        return users, 0
    }
    return users, total
}

// EditUser 编辑用户信息
func EditUser(id int, data *User) int {
    var user User
    var maps = make(map[string]interface{})
    maps["username"] = data.Username
    maps["role"] = data.Role
    err = db.Model(&user).Where("id = ? ", id).Updates(maps).Error
    if err != nil {
        return errmsg.ERROR
    }
    return errmsg.SUCCESS
}

// ChangePassword 修改密码
func ChangePassword(id int, data *User) int {
    //var user User
    //var maps = make(map[string]interface{})
    //maps["password"] = data.Password

    err = db.Select("password").Where("id = ?", id).Updates(&data).Error
    if err != nil {
        return errmsg.ERROR
    }
    return errmsg.SUCCESS
}

// DeleteUser 删除用户
func DeleteUser(id int) int {
    var user User
    err = db.Where("id = ? ", id).Delete(&user).Error
    if err != nil {
        return errmsg.ERROR
    }
    return errmsg.SUCCESS
}

// BeforeCreate 密码加密&权限控制
// 使用 scrypt 算法加密
// 钩子函数
func (u *User) BeforeCreate(_ *gorm.DB) (err error) {
    u.Password = ScryptPw(u.Password)
    u.Role = 2
    return nil
}

func (u *User) BeforeUpdate(_ *gorm.DB) (err error) {
    u.Password = ScryptPw(u.Password)
    return nil
}

// ScryptPw 生成密码
func ScryptPw(password string) string {
    const cost = 10

    HashPw, err := bcrypt.GenerateFromPassword([]byte(password), cost)
    if err != nil {
        log.Fatal(err)
    }

    return string(HashPw)
}

// CheckLogin 后台登录验证
func CheckLogin(username string, password string) (User, int) {
    var user User
    var PasswordErr error

    db.Where("username = ?", username).First(&user)

    PasswordErr = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))

    if user.ID == 0 {
        return user, errmsg.ERROR_USER_NOT_EXIST
    }
    if PasswordErr != nil {
        return user, errmsg.ERROR_PASSWORD_WRONG
    }
    if user.Role != 1 {
        return user, errmsg.ERROR_USER_NO_RIGHT
    }
    return user, errmsg.SUCCESS
}

// CheckLoginFront 前台登录
func CheckLoginFront(username string, password string) (User, int) {
    var user User
    var PasswordErr error

    db.Where("username = ?", username).First(&user)

    PasswordErr = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
    if user.ID == 0 {
        return user, errmsg.ERROR_USER_NOT_EXIST
    }
    if PasswordErr != nil {
        return user, errmsg.ERROR_PASSWORD_WRONG
    }
    return user, errmsg.SUCCESS
}

// 查询用户写的文章
func GetUserArticles(id uint) ([]gin.H, int64, int) {
    var articles []Article
    var total int64
    err := db.Select("article.id, title, img").
        Where("article.user_id = ?", id).Order("Created_At DESC").Find(&articles).Error
    if err != nil { return nil, 0, errmsg.ERROR }
    db.Model(&articles).Where("article.user_id = ?", id).Count(&total)
    
    var result []gin.H

    for _, article := range articles {
        result = append(result, gin.H{
            "id":    article.ID,
            "title": article.Title,
            "img":   article.Img,
        })
    }
    return result, total, errmsg.SUCCESS
}
